﻿using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Deployment.Application;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Web;
using System.Windows.Forms;
using RedRiver.Framework.AppFramework.Properties;
using RedRiver.Framework.XtraCommon.FormHelper;
using RedRiver.Framework.XtraCommon.Models;
using Resources=RedRiver.Framework.XtraCommon.Properties.Resources;

namespace RedRiver.Framework.AppFramework{
    public class CheckDeployUpdate{
        private const string ConfigFile = "RedRiver.Framework.AppFramework.exe.config";

        internal static void UpdateApplication(){
            try{
                if (ApplicationDeployment.IsNetworkDeployed){
                    var deployment = ApplicationDeployment.CurrentDeployment;

                    if (deployment.UpdateLocation != null){
                        XtraMessageForm.ShowMessage("检查可用更新 - " + deployment.UpdateLocation);
                        deployment.CheckForUpdateCompleted += CheckForUpdateCompleted;
                        deployment.CheckForUpdateProgressChanged += CheckForUpdateProgressChanged;
                        deployment.CheckForDetailedUpdate();
                        XtraMessageForm.Hiden();
                    }
                    if (deployment.ActivationUri != null){
                        XtraMessageForm.ShowMessage("更新配置文件...");
                        string queryString = deployment.ActivationUri.Query;
                        //configUrl
                        NameValueCollection nameValueTable = HttpUtility.ParseQueryString(queryString);
                        string configUrl = nameValueTable["configUrl"];
                        if (!string.IsNullOrEmpty(configUrl)){
                            UpdateConfigFiles(deployment, configUrl);
                        }
                        XtraMessageForm.Hiden();
                    }
                    try{
                        File.Copy(Path.Combine(Application.UserAppDataPath, ConfigFile),
                                  Path.Combine(Application.StartupPath, ConfigFile), true);
                    } catch (Exception ex){
                        XtraMessageForm.ShowException(ex.Message, ex, 3);
                    }
                } else{
                    XtraMessageForm.ShowMessage(Resources.Warning, "应用程序不是通过网络发布的,无法更新", 3);
                }
            }catch(Exception e){
                Trace.WriteLine(e.ToString());
                XtraMessageForm.ShowMessage(Resources.Warning, e.Message, 3);
            }
        }

        /// <summary>
        /// 更新配置文件
        /// </summary>
        private static void UpdateConfigFiles(ApplicationDeployment deployment, string configUrl){
            WebClient webClient = null;
            try{
                XtraMessageForm.ShowMessage("正在更新配置文件...");
                Uri configUri;
                if (Uri.TryCreate(deployment.ActivationUri, configUrl, out configUri)){
                    webClient = new WebClient();

                    webClient.DownloadFile(new Uri(configUri, ConfigFile),
                                           Path.Combine(Application.UserAppDataPath, ConfigFile));
                    //var navInfoFile = Path.GetFileName(NavBarInfo.DefaultInfoFilePath);
                    webClient.DownloadFile(new Uri(configUri, NavBarInfo.DefaultInfoFileName), NavBarInfo.DefaultInfoFilePath);
                    XtraMessageForm.ShowMessage("重新加载配置文件...");
                    Settings.Default.Reload();
                    //Settings.Default.Reset();
                    /*var result = MessageBox.Show("配置文件已经更新,是否重新启动程序", "提示信息", MessageBoxButtons.YesNo,
                                                 MessageBoxIcon.Question);
                    if(result==DialogResult.Yes){
                        //Application.Restart();
                       Properties.Settings.Default.Reload();
                    }*/
                }
            } catch (Exception ex){
                XtraMessageForm.ShowException("更新配置文件发生异常,", ex, 5);
            } finally{
                if (webClient != null){
                    webClient.Dispose();
                }
            }
        }

        private static void CheckForUpdateProgressChanged(object sender, DeploymentProgressChangedEventArgs e){
            XtraMessageForm.ShowMessage(String.Format("正在下载: {0}. {1:D}K / {2:D}K", GetProgressString(e.State),
                                                      e.BytesCompleted/1024, e.BytesTotal/1024));
        }

        private static string GetProgressString(DeploymentProgressState state){
            switch (state){
                case DeploymentProgressState.DownloadingApplicationFiles:
                    return "正在下载组成应用程序的 DLL 和数据文件";
                case DeploymentProgressState.DownloadingApplicationInformation:
                    return "正在下载应用程序清单";
                case DeploymentProgressState.DownloadingDeploymentInformation:
                    return "正在下载部署清单";
            }
            return string.Empty;
        }

        private static void CheckForUpdateCompleted(object sender, CheckForUpdateCompletedEventArgs e){
            if (e.Error != null){
                XtraMessageForm.ShowException("错误:不能更新应用程序,\r\n" + e.Error.Message + "\r\n请联系系统管理员", e.Error);
                return;
            }
            if (e.Cancelled){
                XtraMessageForm.ShowMessage(Resources.Warning, "更新已被取消.", 3);
            }

            // Ask the user if they would like to update the application now.    
            if (e.UpdateAvailable){
                if (!e.IsUpdateRequired){
                    DialogResult result = MessageBox.Show(@"有一个可用更新,现在是否更新程序?", @"可用更新", MessageBoxButtons.OKCancel);
                    if (DialogResult.OK == result){
                        BeginUpdate();
                    }
                } else{
                    MessageBox.Show(
                        @"当前有一个可用更新,请保存正在处理的数据,更新完成后会重新启动程序");
                    BeginUpdate();
                }
            }
        }

        private static void BeginUpdate(){
            ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
            ad.UpdateCompleted += OnUpdateCompleted;

            // Indicate progress in the application's status bar.    
            ad.UpdateProgressChanged += OnUpdateProgressChanged;

            // 开始异步更新    
            ad.UpdateAsync();
        }

        private static void OnUpdateProgressChanged(object sender, DeploymentProgressChangedEventArgs e){
            String progressText = String.Format("{0:D}K out of {1:D}K downloaded - {2:D}% complete",
                                                e.BytesCompleted/1024, e.BytesTotal/1024, e.ProgressPercentage);
            XtraMessageForm.ShowMessage(progressText);
        }

        private static void OnUpdateCompleted(object sender, AsyncCompletedEventArgs e){
            if (e.Cancelled){
                MessageBox.Show(@"更新进程被取消.", Properties.Resources.MsgTitle, MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            if (e.Error != null){
                XtraMessageForm.ShowException("无法安装程序的最新版本", e.Error);
                return;
            }

            DialogResult result = MessageBox.Show(@"应用程序已被更新,是否重新启动程序? ", Properties.Resources.MsgTitle, MessageBoxButtons.OKCancel,
                                                  MessageBoxIcon.Question);
            if (DialogResult.OK == result){
                Application.Restart();
            }
        }
    }
}